#include "bitmap.h"
#include "debug.h"
#include "string.h"

void bitmap_init(struct bitmap* btmp){
    memset(btmp->bits, 0, btmp->btmp_bytes_len);
}
bool bitmap_scan_test(struct bitmap* btmp, uint32_t idx_bit){
    /* 找到对应的字节 */
    uint32_t _idx_byte = idx_bit / 8;
    /* 找到对应的位 */
    uint32_t _idx_bit = idx_bit % 8;
    /* 如果相应的位置1就返回1 否则0 */
    return (bool)(btmp->bits[_idx_byte] & (BITMAP_MASK << _idx_bit));
}
int bitmap_scan(struct bitmap* btmp, uint32_t cnt){
    uint8_t* _bits = btmp->bits;
    uint32_t _idx_byte = 0;
    /* 穷举法，直到找到一个不全为0的字节 */
    while(_bits[_idx_byte] == 0xff && _idx_byte < btmp->btmp_bytes_len)
        _idx_byte++;

    ASSERT(_idx_byte < btmp->btmp_bytes_len);
    
    uint8_t _idx_bit = 0;

    /* 找一个不为1的位 */
    
    // while((_bits[_idx_byte] & (BITMAP_MASK << _idx_bit)));
    /* 2023/11/05 13:04 修复卡死问题 */
    while((_bits[_idx_byte] & (BITMAP_MASK << _idx_bit++)));
    _idx_bit --;

    uint32_t _idx_start = _idx_byte * 8 + _idx_bit;
    if(cnt == 1){
        return _idx_start;
    }
    uint32_t _cnt = 1;
    /* 获取左边还有多少位可以判断 */
    uint32_t _idx_bit_left = (btmp->btmp_bytes_len * 8 - _idx_start);
    /* 下一个要查找的位 */
    uint32_t _next_idx_bit = _idx_start + 1;
    /* 先将开始比特置为-1 */
    _idx_start = -1;
    while(_idx_bit_left-- > 0){
        /* 如果找到连续的可用位 就计数+1 */
        if(bitmap_scan_test(btmp, _next_idx_bit) == 0){
            _cnt ++;
        }else{
            /* 找不到连续可用的位 就清零 */
            _cnt = 0;
        }
        /* 找到了cnt个连续可用的位 */
        if(_cnt == cnt){
            /* 推出cnt个连续可用的位起始位 */
            _idx_start = _next_idx_bit - _cnt + 1;
            break;
        }
        _next_idx_bit ++;
    }
    return _idx_start;
}
void bitmap_set(struct bitmap* btmp, uint32_t idx_bit, int8_t value){
    ASSERT(value == 1 || value == 0);
    /* 找到对应的字节 */
    uint32_t _idx_byte = idx_bit / 8;
    /* 找到对应的位 */
    uint32_t _idx_bit = idx_bit % 8;
    uint8_t* _idx_value = &(btmp->bits[_idx_byte]);
    if(value == 0){
        *_idx_value &= ~(BITMAP_MASK << _idx_bit);
    }else{
        *_idx_value |= (BITMAP_MASK << _idx_bit);
    }
}